<template>
  <NDrawer v-model:show="visible" display-directive="show" :width="800">
    <NDrawerContent :title="title" :native-scrollbar="false" closable>
      <NForm ref="formRef" :model="model" :rules="rules" label-placement="left" :label-width="120">
        <NGrid :cols="24" :x-gap="18">
          <NFormItemGridItem :span="12" :label="$t('dataplatform.datamodel.name')" path="name">
            <NInput v-model:value="model.name" :placeholder="$t('common.pleaseEnter')" />
          </NFormItemGridItem>
          <NFormItemGridItem :span="12" :label="$t('dataplatform.datamodel.tableName')" path="tableName">
            <NInput v-model:value="model.tableName" :placeholder="$t('common.pleaseEnter')" :disabled="operateType === 'edit'" />
          </NFormItemGridItem>
          <NFormItemGridItem :span="12" :label="$t('dataplatform.datamodel.tableType')" path="tableType">
            <NSelect v-model:value="model.tableType" :options="tableTypeOptions" :placeholder="$t('common.pleaseSelect')" />
          </NFormItemGridItem>
          <NFormItemGridItem :span="12" :label="$t('dataplatform.datamodel.bucketNum')" path="bucketNum">
            <NInputNumber v-model:value="model.bucketNum" :min="1" :max="128" class="w-full" />
          </NFormItemGridItem>
          <NFormItemGridItem :span="12" :label="$t('dataplatform.datamodel.partitionType')" path="partitionType">
            <NSelect v-model:value="model.partitionType" :options="partitionTypeOptions" :placeholder="$t('common.pleaseSelect')" clearable />
          </NFormItemGridItem>
          <NFormItemGridItem :span="12" :label="$t('dataplatform.datamodel.partitionColumn')" path="partitionColumn">
            <NSelect v-model:value="model.partitionColumn" :options="fieldOptions" :placeholder="$t('common.pleaseSelect')" clearable />
          </NFormItemGridItem>
          <NFormItemGridItem :span="12" :label="$t('dataplatform.datamodel.bucketColumn')" path="bucketColumn">
            <NSelect v-model:value="model.bucketColumn" :options="fieldOptions" :placeholder="$t('common.pleaseSelect')" clearable />
          </NFormItemGridItem>
          <NFormItemGridItem :span="12" :label="$t('dataplatform.datamodel.syncToDoris')">
            <NSwitch v-model:value="model.syncToDoris" />
          </NFormItemGridItem>
          <NFormItemGridItem :span="24" :label="$t('dataplatform.datamodel.description')">
            <NInput v-model:value="model.description" type="textarea" :rows="2" :placeholder="$t('common.pleaseEnter')" />
          </NFormItemGridItem>
          <NFormItemGridItem v-if="operateType === 'edit'" :span="24" :label="$t('dataplatform.datamodel.changeDescription')">
            <NInput v-model:value="model.changeDescription" type="textarea" :rows="2" :placeholder="$t('common.pleaseEnter')" />
          </NFormItemGridItem>
          <NFormItemGridItem :span="24" :label="$t('dataplatform.datamodel.fields')" path="fields">
            <div class="w-full">
              <NButton type="primary" size="small" @click="handleAddField">
                <template #icon>
                  <icon-ic-round-plus class="text-icon" />
                </template>
                {{ $t('dataplatform.datamodel.addField') }}
              </NButton>
              <NDataTable
                :columns="fieldColumns"
                :data="model.fields"
                :max-height="400"
                :scroll-x="1200"
                class="mt-2"
              />
            </div>
          </NFormItemGridItem>
        </NGrid>
      </NForm>
      <template #footer>
        <NSpace justify="end">
          <NButton @click="closeDrawer">{{ $t('common.cancel') }}</NButton>
          <NButton type="primary" @click="handleSubmit">{{ $t('common.confirm') }}</NButton>
        </NSpace>
      </template>
    </NDrawerContent>
  </NDrawer>
</template>

<script setup lang="tsx">
import { computed, reactive, ref, watch } from 'vue';
import type { FormInst, FormRules, SelectOption } from 'naive-ui';
import { NButton, NCheckbox, NInput, NInputNumber, NSelect } from 'naive-ui';
import { $t } from '@/locales';
import { addDataModel, getDataModel, updateDataModel, type DataModel, type DataModelDTO, type ModelField } from '@/service/api/dataplatform/datamodel';

interface Props {
  visible: boolean;
  operateType: 'add' | 'edit';
  rowData?: DataModel | null;
}

const props = defineProps<Props>();

interface Emits {
  (e: 'update:visible', visible: boolean): void;
  (e: 'submitted'): void;
}

const emit = defineEmits<Emits>();

const visible = computed({
  get() {
    return props.visible;
  },
  set(visible) {
    emit('update:visible', visible);
  }
});

const title = computed(() => (props.operateType === 'add' ? $t('common.add') : $t('common.edit')));

const formRef = ref<HTMLElement & FormInst>();

const model: DataModelDTO = reactive({
  name: '',
  tableName: '',
  tableType: 'DUPLICATE',
  bucketNum: 10,
  fields: [],
  syncToDoris: false
});

const rules: FormRules = {
  name: [{ required: true, message: $t('common.required'), trigger: 'blur' }],
  tableName: [
    { required: true, message: $t('common.required'), trigger: 'blur' },
    { pattern: /^[a-zA-Z][a-zA-Z0-9_]*$/, message: $t('dataplatform.datamodel.tableNameFormat'), trigger: 'blur' }
  ],
  tableType: [{ required: true, message: $t('common.required'), trigger: 'change' }],
  fields: [{ required: true, message: $t('common.required'), trigger: 'change' }]
};

const tableTypeOptions: SelectOption[] = [
  { label: 'DUPLICATE', value: 'DUPLICATE' },
  { label: 'AGGREGATE', value: 'AGGREGATE' },
  { label: 'UNIQUE', value: 'UNIQUE' }
];

const partitionTypeOptions: SelectOption[] = [
  { label: 'RANGE', value: 'RANGE' },
  { label: 'LIST', value: 'LIST' }
];

const fieldTypeOptions: SelectOption[] = [
  { label: 'INT', value: 'INT' },
  { label: 'BIGINT', value: 'BIGINT' },
  { label: 'VARCHAR', value: 'VARCHAR' },
  { label: 'CHAR', value: 'CHAR' },
  { label: 'DECIMAL', value: 'DECIMAL' },
  { label: 'DATE', value: 'DATE' },
  { label: 'DATETIME', value: 'DATETIME' },
  { label: 'BOOLEAN', value: 'BOOLEAN' },
  { label: 'TEXT', value: 'TEXT' }
];

const aggregateTypeOptions: SelectOption[] = [
  { label: 'SUM', value: 'SUM' },
  { label: 'MAX', value: 'MAX' },
  { label: 'MIN', value: 'MIN' },
  { label: 'REPLACE', value: 'REPLACE' },
  { label: 'REPLACE_IF_NOT_NULL', value: 'REPLACE_IF_NOT_NULL' }
];

const fieldOptions = computed(() => {
  return model.fields
    .filter(f => f.name && f.name.trim() !== '')
    .map(f => ({ label: f.name, value: f.name }));
});

const fieldColumns = computed(() => {
  const baseColumns: any[] = [
    {
      key: 'name',
      title: () => $t('dataplatform.datamodel.fieldName'),
      width: 150,
      render: (row: ModelField, index: number) => (
        <NInput 
          value={row.name} 
          onUpdateValue={(value: string) => { row.name = value; }}
          placeholder={$t('common.pleaseEnter')} 
          onBlur={() => validateFieldName(row, index)} 
        />
      )
    },
    {
      key: 'type',
      title: () => $t('dataplatform.datamodel.fieldType'),
      width: 120,
      render: (row: ModelField) => (
        <NSelect 
          value={row.type} 
          onUpdateValue={(value: string) => { row.type = value; }}
          options={fieldTypeOptions} 
          placeholder={$t('common.pleaseSelect')} 
        />
      )
    },
    {
      key: 'length',
      title: () => $t('dataplatform.datamodel.length'),
      width: 100,
      render: (row: ModelField) => {
        if (needsLength(row.type)) {
          return <NInputNumber value={row.length} onUpdateValue={(value: number) => { row.length = value; }} min={1} size="small" />;
        }
        return null;
      }
    },
    {
      key: 'scale',
      title: () => $t('dataplatform.datamodel.scale'),
      width: 100,
      render: (row: ModelField) => {
        if (row.type === 'DECIMAL') {
          return <NInputNumber value={row.scale} onUpdateValue={(value: number) => { row.scale = value; }} min={0} size="small" />;
        }
        return null;
      }
    },
    {
      key: 'nullable',
      title: () => $t('dataplatform.datamodel.nullable'),
      width: 80,
      align: 'center',
      render: (row: ModelField) => <NCheckbox checked={row.nullable} onUpdateChecked={(value: boolean) => { row.nullable = value; }} />
    },
    {
      key: 'primaryKey',
      title: () => $t('dataplatform.datamodel.primaryKey'),
      width: 80,
      align: 'center',
      render: (row: ModelField) => <NCheckbox checked={row.primaryKey} onUpdateChecked={(value: boolean) => { row.primaryKey = value; }} />
    }
  ];

  if (model.tableType === 'AGGREGATE') {
    baseColumns.push({
      key: 'aggregateType',
      title: () => $t('dataplatform.datamodel.aggregateType'),
      width: 120,
      render: (row: ModelField) => {
        if (!row.primaryKey) {
          return <NSelect value={row.aggregateType} onUpdateValue={(value: string) => { row.aggregateType = value; }} options={aggregateTypeOptions} placeholder={$t('common.pleaseSelect')} size="small" />;
        }
        return null;
      }
    });
  }

  baseColumns.push(
    {
      key: 'comment',
      title: () => $t('dataplatform.datamodel.comment'),
      minWidth: 150,
      render: (row: ModelField) => <NInput value={row.comment} onUpdateValue={(value: string) => { row.comment = value; }} placeholder={$t('common.pleaseEnter')} />
    },
    {
      key: 'actions',
      title: () => $t('common.action'),
      width: 80,
      align: 'center',
      render: (_row: ModelField, index: number) => (
        <NButton size="small" type="error" onClick={() => handleDeleteField(index)}>
          {$t('common.delete')}
        </NButton>
      )
    }
  );

  return baseColumns;
});

function needsLength(type: string) {
  return ['VARCHAR', 'CHAR', 'DECIMAL'].includes(type);
}

function handleAddField() {
  model.fields.push({
    name: '',
    type: 'VARCHAR',
    length: 255,
    nullable: true,
    primaryKey: false
  });
}

function handleDeleteField(index: number) {
  model.fields.splice(index, 1);
}

function validateFieldName(field: ModelField, index: number) {
  if (!field.name) return;

  if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(field.name)) {
    window.$message?.warning($t('dataplatform.datamodel.fieldNameFormat'));
    return;
  }

  const duplicateIndex = model.fields.findIndex((f, i) => i !== index && f.name === field.name);
  if (duplicateIndex !== -1) {
    window.$message?.warning($t('dataplatform.datamodel.fieldNameDuplicate'));
  }
}

async function handleSubmit() {
  await formRef.value?.validate();

  if (model.fields.length === 0) {
    window.$message?.warning($t('dataplatform.datamodel.fieldsRequired'));
    return;
  }

  for (const field of model.fields) {
    if (!field.name) {
      window.$message?.warning($t('dataplatform.datamodel.fieldNameRequired'));
      return;
    }
    if (!field.type) {
      window.$message?.warning($t('dataplatform.datamodel.fieldTypeRequired'));
      return;
    }
  }

  const hasPrimaryKey = model.fields.some(f => f.primaryKey);
  if ((model.tableType === 'UNIQUE' || model.tableType === 'AGGREGATE') && !hasPrimaryKey) {
    window.$message?.warning($t('dataplatform.datamodel.primaryKeyRequired'));
    return;
  }

  if (model.tableType === 'AGGREGATE') {
    for (const field of model.fields) {
      if (!field.primaryKey && !field.aggregateType) {
        window.$message?.warning($t('dataplatform.datamodel.aggregateTypeRequired'));
        return;
      }
    }
  }

  const request = props.operateType === 'add' ? addDataModel(model) : updateDataModel(model);
  const { error } = await request;
  if (!error) {
    window.$message?.success($t('common.operationSuccess'));
    closeDrawer();
    emit('submitted');
  }
}

function closeDrawer() {
  visible.value = false;
}

watch(visible, () => {
  if (visible.value) {
    if (props.operateType === 'add') {
      Object.assign(model, {
        id: undefined,
        name: '',
        tableName: '',
        tableType: 'DUPLICATE',
        partitionType: undefined,
        partitionColumn: undefined,
        bucketColumn: undefined,
        bucketNum: 10,
        fields: [],
        description: undefined,
        projectId: undefined,
        changeDescription: undefined,
        syncToDoris: false
      });
    } else if (props.rowData) {
      getDataModel(props.rowData.id!).then(({ data }) => {
        Object.assign(model, {
          id: data.id,
          name: data.name,
          tableName: data.tableName,
          tableType: data.tableType,
          partitionType: data.partitionType,
          partitionColumn: data.partitionColumn,
          bucketColumn: data.bucketColumn,
          bucketNum: data.bucketNum,
          fields: JSON.parse(data.fields as any),
          description: data.description,
          projectId: data.projectId,
          syncToDoris: false
        });
      });
    }
  }
});
</script>

<style scoped lang="scss"></style>
